import CryptoJS from 'crypto-js'
import Qs from 'qs'
import { formatJSON, removeLocalStorage } from "@/common.js"
import { Message } from 'view-design'
import router from "@/router/index.js"
import {isDebug} from "@/utils/network.js"
/**
 ********************************************************
 * 加密解密函数
 * encrypt： 加密函数
 * decrypt： 解密函数
 ********************************************************
 */
const utf8Key = CryptoJS.enc.Utf8.parse(process.env.VUE_APP_KEY) // 秘钥
const options = { iv: CryptoJS.enc.Utf8.parse(process.env.VUE_APP_IV), padding: CryptoJS.pad.Pkcs7, mode: CryptoJS.mode.CBC } // 生成配置项
export const encrypt = e => CryptoJS.TripleDES.encrypt(e, utf8Key, options).toString() // 加密
export const decrypt = e => CryptoJS.enc.Utf8.stringify(CryptoJS.TripleDES.decrypt(e.replace(/\s/g, ''), utf8Key, options)) // 解密
/*
 ********************************************************
 ******************网络请求相关***************************
 ********************************************************
 */
// 移除登录标记信息
export const removeTokenSign = () => { removeLocalStorage('token');removeLocalStorage('userInfo') }
// 处理入参 
export const commonParam = { cityLcode: '320400', deviceId: 'PC', deviceType: 'PC', clientTime: new Date().getTime() }
export const resolveParams = params => Qs.stringify(isDebug ? { ...formatJSON(params || {}), debug: 1 } : { data: encrypt(JSON.stringify({ ...formatJSON(params || {}), ...commonParam })) })
// 几秒内的一次性提示
export const onceTipInSecond = (function (){
  let isAllowMsg = true
  return function (msg){
    if(!isAllowMsg) { return false }
    isAllowMsg = false
    setTimeout(() => isAllowMsg = true, 5e3)
    Message.error(msg)
    removeTokenSign()
    router.replace({ path: "/login" }).catch(() => {})
  }
})()
/**
 * 处理异常
 * @param {*} res 
 * @param {String} url 
 * @param {*} type 
 * @param {*} resolve 
 * @param {*} reject 
 */
export const processError = function (res, url, type = 0, resolve, reject) {
  // res = safeGet(() => res.errcode, false) ? res : JSON.parse(decrypt(res))
  const { errcode, data, errmsg } = res
  if (errcode == 10200 || errcode == 10210 || errcode == 401) { // 未登录和token过期
    onceTipInSecond('请登录')
    reject('token过期，请重新登录')
  } else if (type == 0) {
    resolve(res)
  } else if (errcode == 200) {
    resolve(data)
  } else { // 其他异常
    Message.error(JSON.stringify(errmsg) || `${url}报错，errmsg为空`)
    reject(JSON.stringify(errmsg) || `${url}报错，errmsg为空`)
  }
}
/**
 * 防止重复请求，N毫秒内连续请求，只会请求一次。并且，第一次接口尚未返回则第二次请求被拒绝。主要用于新增操作
 * @param {*} url 请求的url地址
 * @param {*} params 请求参数
 * @param {*} type 返回数据类型  1代表只返回data    0代表不做任何处理直接返回格式：{code:xx, data:xx, msg:xx}
 * @returns 
 * @举例 const res = await this.$startPost('/apprepair/editRepair', {id:1, name:'zz'})
 */
export const startPost = (function (wait) {
  let start = +new Date() // 记录第一次点击时的时间戳
  const reqRecord = new Map() // 记录已发起但未返回的请求： url<--->reject方法
  return function (url, params, defaultVal = {}, type = 1) {
    let end = +new Date() // 记录第一次以后的每次点击的时间戳
    if (end - start >= wait || reqRecord.size == 0) { // 1.5s内连续点击，只请求一次（节流时间）
      start = end // 执行处理函数后，将结束时间设置为开始时间，重新开始记时
      return new Promise((resolve, reject) => {
        if (reqRecord.get(url)) { return Promise.reject(`取消当前请求${url}`) }
        reqRecord.set(url, url)
        return service.post(url, resolveParams(params)).then(res => processError(res, url, defaultVal, type, resolve, reject)).finally(() => reqRecord.delete(url))
      })
    }
  }
})(1500)
/**
 * 可以重复请求，连续重复的url请求，只会渲染最后一次请求返回的结果。主要用于查询操作
 * @param {String} url 请求的url地址
 * @param {Object} params 请求参数
 * @param {*} type 返回数据类型  1代表只返回data    0代表不做任何处理直接返回格式：{code:xx, data:xx, msg:xx}
 * @returns 
 * @举例 const res = await this.$endPost('/apprepair/editRepair', {id:1, name:'zz'})
 */
export const endPost = (function () {
  const reqRecord = new Map() // 记录已发起但未返回的请求： url<---->reject方法
  return function (url, params, type = 1) {
    const req = () => service.post(url, resolveParams(params))
    return new Promise((resolve, reject) => {
      if (reqRecord.get(url)) { reqRecord.get(url)(`放弃上次请求的渲染${url}`) } // 放弃请求
      const promiseA = new Promise((_, rej) => reqRecord.set(url, rej))
      return Promise.race([req(), promiseA]).then(res => processError(res, url, type, resolve, reject)).finally(() => reqRecord.delete(url))
    })
  }
})()